/*
*    Phantom Test Driver v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/*
 * PTDDebugPanel.java
 *
 * Created on March 4, 2006, 2:40 PM
 */

package ptd;

import ssi_socket.*;
import ssi_linenumberview.*;
import javax.swing.ImageIcon;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

/**
 *
 * @author  John
 */
public class PTDDebugPanel extends javax.swing.JPanel implements PTDScriptComm, PTDDisplay {
    private PTDScriptPane MyOutput;
    private PTDVariableTable MyVariables;
    private Vector<PTDDebugBreakpoint> BptCmdSet;
    private int BptCtr;
    private int BptCount;
    private int VarCtr;
    private int VarCount;
    private PTDMain MyMain;
    
    boolean bDebugAvailable;
    boolean bLineAvailable;
    String sDebugCmd;
    int DebugAction;
    
    static int DEBUG_NULL = 0;
    static int DEBUG_EVALUATE = 1;
    static int DEBUG_STEP_OVER = 2;
    static int DEBUG_STEP_INTO = 3;
    static int DEBUG_STEP_OUT = 4;
    static int DEBUG_STOP = 5;
    static int DEBUG_GO = 6;
    
    public class PTDDebugBreakpoint{
        // +b LineNumber FilePath
        // -b LineNumber FilePath
        public int LineNumber;
        public String FilePath;
        public int Action;   // 1 = add, 2 = remove
        public int State;    // 1 = sent, 2 = waiting
        
        public String makeCommand(){
            String s;
            s = LineNumber + " " + FilePath;
            return s;
        }
                
        public void set(int iLine, String sFile){
            LineNumber = iLine;
            FilePath = sFile;
        }
        
    }
    
    /** Creates new form PTDDebugPanel */
    public PTDDebugPanel(PTDMain inMain) {
        initComponents();
        
        MyOutput = (new PTDScriptPane());
        MyOutput.bPassive = true;   // Set so text input will go to end of line
        
        MyVariables = new PTDVariableTable();
        
        m_Evaluate.setText("Evaluate");
        m_EvaluateText.setText("");
        
        //((PTDScriptPane)MyOutput).setEditable(false);
        
        bDebugAvailable = false;
        bLineAvailable = false;
        DebugAction = DEBUG_NULL;
        BptCmdSet = new Vector<PTDDebugBreakpoint>();
        
        m_VarListScroll.setViewportView(MyVariables);
        
        VarCtr = 0;
        BptCtr = 0;
        VarCount = 0;
        MyMain = inMain;
        
    }
    
    public void updateLinePtr(String File, int Line){
        // Actually find the script pane with the file first
        
        int i = MyMain.addScriptPane(File);
        if(i == 0){
            return;
        }
        
        PTDScriptPane aPane = MyMain.getActiveScriptPane();
        
        aPane.MyLinePtr.m_LineNum = Line;
        aPane.scrollToLine(Line);       
        
        if(DebugAction == DEBUG_STOP){
            //LineNum = -1;
            aPane.clearDebugPtr();
        }else{
            aPane.MyLineNumView.update();     
        }
        
    }
    
    public void initBptCmds(){
        if(MyMain == null){
            return;
        }
        
        BptCtr = 0;
        PTDScriptPane aScriptPane = null;
        PTDScript aScript = null;
        int cnt = MyMain.getScriptPaneCount();
        int ctr = 0;
        int bcnt = 0;
        int bctr = 0;
        LineIcon anIcon = null;
        
        BptCmdSet.clear();
        for(ctr = 0; ctr < cnt; ctr++){
            aScriptPane = MyMain.getScriptPaneByIndex(ctr);
            if(aScriptPane != null){
                bcnt = aScriptPane.MyBptPtrs.size();
                for(bctr = 0; bctr < bcnt; bctr++){
                    anIcon = (LineIcon)aScriptPane.MyBptPtrs.get(bctr);
                    if(anIcon != null){
                        PTDDebugBreakpoint aBpt = new PTDDebugBreakpoint();
                        aScript = aScriptPane.getScript();
                        if(aScript != null){
                            aBpt.set(anIcon.m_LineNum, aScript.myFile);
                            addBptCmd(aBpt);
                        }
                        
                    }
                }
                //public Vector MyBptPtrs;
            }
        }
        
        // Cycle through script panes
        // Get each pane BptIcon
        // Generate Command with Pane file and Bpt Line Number
        // Push on to list
        //MyMain.get
    }

    // -----------------------------------------------------
    public void addBptCmd(int iLine, String sPath){
        PTDDebugBreakpoint newBpt = new PTDDebugBreakpoint();
        newBpt.set(iLine, sPath);
        addBptCmd(newBpt);
    }

    // -----------------------------------------------------
    public void removeBptCmd(int iLine, String sPath){
        PTDDebugBreakpoint newBpt = new PTDDebugBreakpoint();
        newBpt.set(iLine, sPath);
        removeBptCmd(newBpt);
    }

    
    // -----------------------------------------------------
    public void addBptCmd(PTDDebugBreakpoint inBpt){
        if(inBpt.FilePath.length() <= 0){
            return;
        }

        int sz = BptCmdSet.size();
        int ctr = 0;
        BptCtr = 0;
        for(ctr = 0; ctr < sz; ctr++){
            PTDDebugBreakpoint aBpt = (PTDDebugBreakpoint)BptCmdSet.get(ctr);
            if(aBpt.LineNumber == inBpt.LineNumber){
                if(aBpt.FilePath.compareTo(inBpt.FilePath) == 0){
                    aBpt.Action = 1;  // Make it need to add
                    aBpt.State = 1;   // Make it need to send
                    return;
                }
            }
        }
        inBpt.Action = 1;
        inBpt.State = 1;
        BptCmdSet.add((PTDDebugBreakpoint)inBpt);
    }
    
    // -----------------------------------------------------
    public void removeBptCmd(PTDDebugBreakpoint inBpt){
        if(inBpt.FilePath.length() <= 0){
            return;
        }
        int sz = BptCmdSet.size();
        int ctr = 0;
        BptCtr = 0;
        Main.debug_out("Removing Breakpoint");
        for(ctr = 0; ctr < sz; ctr++){
            PTDDebugBreakpoint aBpt = (PTDDebugBreakpoint)BptCmdSet.get(ctr);
            if(aBpt.LineNumber == inBpt.LineNumber){
                if(aBpt.FilePath.compareTo(inBpt.FilePath) == 0){
                    aBpt.Action = 2;   // Make it need to remove
                    aBpt.State = 1;    // Make it need to send
                    //BptCmdSet.remove(ctr);   // Do not remove here
                    return;
                }
            }
        }
    }
    
    // -----------------------------------------------------
    public void setOutput(PTDScriptPane newPane){
        MyOutput = newPane;
        MyOutput.bPassive = true;
        m_OutputScroll.setViewportView((java.awt.Component)(MyOutput));
    }
    
    // -----------------------------------------------------
    public PTDDisplay getOutput(){
        return (PTDDisplay)MyOutput;
    }
    
    // -----------------------------------------------------
    public int startSuite(String Name){
        return 0;
    }
    
    // -----------------------------------------------------
    public int startTestcase(String Name){
        return 0;
    }

    // -----------------------------------------------------
    public int startScript(String Name){
        return 0;
    }
    
    public int stopSuite(){
        return 0;
    }
    
    public int stopTestcase(){
        return 0;
    }    

    public int stopScript(){
        return 0;
    }    
    
    public int startProcessor(int Type, String Name){
        return 0;
    }

    public int stopProcessor(){
        return 0;
    }

    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jComboBox1 = new javax.swing.JComboBox();
        m_Evaluate = new javax.swing.JButton();
        m_EvaluateText = new javax.swing.JTextField();
        m_SplitPane = new javax.swing.JSplitPane();
        m_VarListScroll = new javax.swing.JScrollPane();
        m_VarListTable = new javax.swing.JTable();
        m_OutputScroll = new javax.swing.JScrollPane();

        setLayout(new java.awt.GridBagLayout());

        m_Evaluate.setFont(new java.awt.Font("Arial", 0, 12)); // NOI18N
        m_Evaluate.setToolTipText("Click to evaluate a command");
        m_Evaluate.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        m_Evaluate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                m_EvaluateActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(0, 0, 1, 4);
        add(m_Evaluate, gridBagConstraints);

        m_EvaluateText.setToolTipText("Enter command to evaluate here");
        m_EvaluateText.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                m_EvaluateTextKeyTyped(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        add(m_EvaluateText, gridBagConstraints);

        m_SplitPane.setDividerSize(4);
        m_SplitPane.setResizeWeight(0.5);

        m_VarListScroll.setToolTipText("Enter variable names to watch");

        m_VarListTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        m_VarListScroll.setViewportView(m_VarListTable);

        m_SplitPane.setRightComponent(m_VarListScroll);
        m_SplitPane.setLeftComponent(m_OutputScroll);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weighty = 1.0;
        add(m_SplitPane, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents

    private void m_EvaluateTextKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_m_EvaluateTextKeyTyped
        
        //if(evt.getKeyCode() == evt.VK_ENTER){
        //    DebugAction = DEBUG_EVALUATE;
        //    bDebugAvailable = true;
        //}
        if(evt.getKeyChar() == '\n'){
            //DebugAction = DEBUG_EVALUATE;
            setDebugAvailable(DEBUG_EVALUATE);
            //bDebugAvailable = true;
        }
    }//GEN-LAST:event_m_EvaluateTextKeyTyped

    
    private void m_EvaluateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_m_EvaluateActionPerformed
        //DebugAction = DEBUG_EVALUATE;
        //bDebugAvailable = true;
        setDebugAvailable(DEBUG_EVALUATE);
    }//GEN-LAST:event_m_EvaluateActionPerformed
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox jComboBox1;
    private javax.swing.JButton m_Evaluate;
    private javax.swing.JTextField m_EvaluateText;
    public javax.swing.JScrollPane m_OutputScroll;
    private javax.swing.JSplitPane m_SplitPane;
    private javax.swing.JScrollPane m_VarListScroll;
    public javax.swing.JTable m_VarListTable;
    // End of variables declaration//GEN-END:variables
    
    
    // -----------------------------------------------------
    public void Kill(){
        //if(MainThread != null){
        //    MainThread.Kill();
        //}
    }
    
    // -----------------------------------------------------
    public String getNextLine(){
        return MyOutput.getInput();
    }

    
    // -----------------------------------------------------    
    public int display(String Output){        
        
        
        
        if(Output.length() <= 0) return 1;  // So buffer blank buffer doesnt accidentally destroy segment position
        
       // VarCount = MyVariables.getRowCount();
       // if(VarCtr <= VarCount){
       //     return displayDebug(Output);
       // }
        
        return MyOutput.display(Output);
    }
    
    public int displayDebug(String Output){
        //Output = Output.replaceAll("\n", "\\\\" + "n");
        //Output = Output.replaceAll("\r", "\\\\" + "r");
        //Output = Output.replaceAll("\t", "\\\\" + "t");
        if(Output.length() > 1024){
            Output = Output.substring(0, 1023) + "...";
        }
        MyVariables.MyModel.setVariableResult(VarCtr-1, Output);
        return 1;
    }
    
    public int displayFormatted(String Output){
        return MyOutput.displayFormatted(Output); 
    }
    
    public int displayError(String Output){
        return MyOutput.displayError(Output);
    }
    
    public int displayWarning(String Output){
        return MyOutput.displayWarning(Output);
    }
    
    public int displayFailure(String Output){
        return MyOutput.displayFailure(Output);
    }



    // -----------------------------------------------------    
    public boolean lineAvailable(){
        MyOutput.bCanGetInput = true;
        if(MyOutput.bInputAvailable){
            MyOutput.bCanGetInput = false;
            return true;
        }else{
            return false;
        }
    }
    
    public void setRunState(int newState){
        PTDScriptPane aPane = MyMain.getActiveScriptPane();
        aPane.clearDebugPtr();
        if(newState == 1){
            clearDebugStates();
        }else{
        }
    }
    
    // -----------------------------------------------------    
    public void reportFault(int iCode, String Message){
        MyOutput.display(Message);
    }
    
    
            //LineNumberView  aLineNumView = (LineNumberView)aScroll.getRowHeader().getView();
        //if(aLineNumView != null){
            
            
            //LineIcon newIcon = new LineIcon();      
            //ImageIcon a = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_CUR_LINE);
            //newIcon.Set(16, a.getImage());
            //aLineNumView.IconMgr.addIcon(newIcon);
        //}

    
    public void setLinePtr(String sPtr){
    //public void setLinePtr(int iPtr, String sFile){
        int start_num = sPtr.indexOf("{");
        int end_num = sPtr.indexOf("}");
        String sLineNum = sPtr.substring(start_num + 1, end_num);  // goes to end_num-1
        String sFile = sPtr.substring(end_num+1);
        int LineNum = Integer.parseInt(sLineNum);
       
        
        updateLinePtr(sFile, LineNum);
    }
    
    
    public int requestDebug(String LineInfo){
        // This *should* be run from within a thread...

        
        // Parse aCmd.Data to get line and file to set pointer
        
        // This stuff needs to be after the command goes out...
        if(VarCtr < 0){
            VarCount = MyVariables.getRowCount();
            VarCtr = 0;
        }
        
        //Main.debug_out("Trying A...");
        

        sDebugCmd = "";
        if(MyVariables.MyModel.getUpdateState() > 0){
            VarCtr = -1;
        }
        
        VarCount = MyVariables.getRowCount();
        
        //Main.debug_out("Trying B...");
        // Keep this as a while
        while(VarCtr < VarCount){
            String s = UpdateVariable(VarCtr);
            VarCtr = VarCtr + 1;
            if(s != null){
                sDebugCmd = "v " + s;
                //s = Thread.getVariableValue(s);
                //MyVariables.MyModel.setVariableResult(VarCtr-1, s);
                //aCmd.Set(SSI_Socket.SSI_VAR_RQST, s.length(), s);
                return 1;
            }
        }
        
        //Main.debug_out("Trying C...");
        
        BptCount = BptCmdSet.size();
        //Main.debug_out("Breakpoint Count:" + BptCount);
        while(BptCtr < BptCount){
            //Main.debug_out("Breakpoint Counter:" + BptCtr + " Count: " + BptCount);
            PTDDebugBreakpoint Bpt = (PTDDebugBreakpoint)BptCmdSet.get(BptCtr);
            BptCtr = BptCtr + 1;
            if(Bpt != null){
                if(Bpt.State == 1){
                    Bpt.State = 2;
                    
                    String s = Bpt.makeCommand();
                    Main.debug_out(s);
                    if(Bpt.Action == 2){
                        BptCmdSet.remove(BptCtr-1); // Minus one because incremented earlier
                        sDebugCmd = "-b " + s;
                        //int iRes = Thread.processDebug("-b " + s);
                        //aCmd.Set(SSI_Socket.SSI_BPT_RMV, s.length(), s);
                    }else{
                        sDebugCmd = "+b " + s;
                        //int iRes = Thread.processDebug("+b " + s);
                        //aCmd.Set(SSI_Socket.SSI_BPT_ADD, s.length(), s);
                    }
                    return 1;
                }
            }
        }
        
        //Main.debug_out("Trying D...");
        // While process Breakpoint Requests (create *and* remove) here...
        // Handle instant add/removes elsewhere... only send breakpoints that
        // will actually be processed (ie, net breakpoint change for the cycle)
        //     public static int SSI_BPT_ADD          = 520;
        //     public static int SSI_BPT_RMV          = 521;
        
        //if(VarCtr == VarCount){
        // All variables have been updated, update line ptr
        //    setLinePtr(aCmd.Data);
        //}
        //setLinePtr(Thread.getDebugLine(), Thread.getDebugFile());
        setLinePtr(LineInfo);
        
        //Main.debug_out("Trying E...");
        
        // If no debug command, and variables done
        if((bDebugAvailable == false) && (VarCtr == VarCount)){
            sDebugCmd = "";
            return 0;
        }
        
        //Main.debug_out("Trying F...");
        
        // Reset variables for next time
        VarCtr = -1;
        BptCtr = 0;
        if(DebugAction == DEBUG_EVALUATE){
            String EvalText = (String)m_EvaluateText.getText();
            m_EvaluateText.setText("");
            addEvalTextItem(EvalText);
            //Thread.processDebug("e " + EvalText);
            sDebugCmd = "e " + EvalText;
        }else if(DebugAction == DEBUG_STEP_OVER){
            //Thread.processDebug("g 1");
            sDebugCmd = "g 1";
        }else if(DebugAction == DEBUG_STEP_INTO){
            //Thread.processDebug("j");
            sDebugCmd = "j";
        }else if(DebugAction == DEBUG_STEP_OUT){
            //Thread.processDebug("o");
            sDebugCmd = "o";
        }else if(DebugAction == DEBUG_GO){
            //Thread.processDebug("g -1");
            sDebugCmd = "g -1";
        }else if(DebugAction == DEBUG_STOP){
            //Thread.processDebug("stop");
            sDebugCmd = "stop";
        }else{
            Main.debug_out("Debug Command Error");
            Main.debug_out(Integer.toString(DebugAction));
        }
        
        
        
        DebugAction = 0;
        bDebugAvailable = false;
        return 1;
    }
    
    public String getDebugCmd(){
        return sDebugCmd;
    }
    
    public String UpdateVariable(int Index){
        String Ret;
        if(Index < 0){
            return null;
        }
        
        return MyVariables.MyModel.getVariableName(Index);
        
    }

    public void go(){
        setDebugAvailable(DEBUG_GO);
    }

    
    public void stepOver(){
        //DebugAction = DEBUG_STEP_OVER;
        //bDebugAvailable = true;
        setDebugAvailable(DEBUG_STEP_OVER);
    }


    public void stepInto(){
        //DebugAction = DEBUG_STEP_INTO;
        //bDebugAvailable = true;
        setDebugAvailable(DEBUG_STEP_INTO);
    }

    public void stepOut(){
        //DebugAction = DEBUG_STEP_OUT;
        //bDebugAvailable = true;
        setDebugAvailable(DEBUG_STEP_OUT);
    }
    
    
    public void stop(){
        //DebugAction = DEBUG_STOP;
        //bDebugAvailable = true;
        setDebugAvailable(DEBUG_STOP);
    }
    
    public void setMain(PTDMain inMain){
        MyMain = inMain;
    }
    
    public PTDMain getMain(){
        return MyMain;
    }

    public void addEvalTextItem(String NewItem){
        
        //m_EvaluateText.insertItemAt(NewItem, 0);
        //m_EvaluateText.addItem(NewItem);
        //m_EvaluateText.setSelectedItem(new String(""));
    }
    
    public void setDebugAvailable(int inAction){
        
        // If hasnt 
        if(bDebugAvailable){
            return;
        }
        DebugAction = inAction;
        bDebugAvailable = true;
    }
    
    public void clearDebugStates(){
        DebugAction = 0;
        bDebugAvailable = false;
    }
    
     public void clearOutput(){
        MyOutput.setText("");
    }
    
}
